/**
 * 
 */
package edu.arizona.bio5.onto.decomposition.persistent.file;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.net.URI;

import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.model.OWLOntologyCreationException;
import org.semanticweb.owlapi.model.OWLOntologyManager;
import org.semanticweb.owlapi.model.OWLOntologyStorageException;

import uk.ac.manchester.cs.graph.io.DOTWriterImpl;
import uk.ac.manchester.cs.graph.io.GraphWriter;
import edu.arizona.bio5.onto.decomposition.Atom;
import edu.arizona.bio5.onto.decomposition.AtomicDecomposition;
import edu.arizona.bio5.onto.decomposition.persistent.ADPersistenceException;
import edu.arizona.bio5.onto.decomposition.persistent.ADPersister;
import edu.arizona.bio5.onto.util.IOUtils;
import edu.arizona.bio5.onto.util.OntologyUtils;

/**
 * Persists an AD as a set of files on disk
 * 
 * @author Pavel Klinov
 *
 */
public class DiskADPersister implements ADPersister {

	private File m_rootDir = null;
	
	public void setRootDir(final File rootDir) {
		m_rootDir = rootDir;
	}
	
	/* 
	 */
	@Override
	public void persist(AtomicDecomposition ad) throws ADPersistenceException {
		//First, some cleanup
		IOUtils.cleanRecursively(m_rootDir);
		
		if (!m_rootDir.exists()) m_rootDir.mkdir();
		//Second, save all the crap
		saveModuleType(ad, m_rootDir);
		saveGraph(ad, m_rootDir);
		saveTermBasedIndex(ad, m_rootDir);
		//TODO adapt to multiple labels
		//saveAtomLabels(ad, m_rootDir);	
		//Finally, serialize axioms
		saveAtoms(ad, m_rootDir);
	}

	private void saveAtoms(AtomicDecomposition ad, File dir) throws ADPersistenceException {
		
		OWLOntologyManager mgr = OWLManager.createOWLOntologyManager();
		
		System.out.print("Finally, saving atoms... ");
		
		for (Atom atom : ad.getAtoms()) {
			
			String fileName = dir.getPath() + "/" + DiskADConstants.ATOM_FILE_PREFIX + atom.getID() + ".owl";
			
			try {
				
				OntologyUtils.serializeAxioms(atom.getAxioms(), mgr, fileName);
				
			} catch (OWLOntologyCreationException e) {

				e.printStackTrace();
				throw new ADPersistenceException("Problem serializing atom's axioms: " + e.getMessage());
			} catch (OWLOntologyStorageException e) {

				e.printStackTrace();
				throw new ADPersistenceException("Problem serializing atom's axioms: " + e.getMessage());
			}
		}
		
		System.out.println("done!");
	}

/*	private void saveAtomLabels(AtomicDecomposition ad, File dir) throws ADPersistenceException {

		try {
			
			System.out.print("Saving labels... ");
			
			File labelFile = FileUtils.createNewFile(dir.getAbsolutePath() + "/" + DiskADConstants.LABELS_FILE);
			Writer writer = new FileWriter(labelFile);
			
			for (Atom atom : ad.getAtoms()) {
				
				Label label = atom.getLabel();
				
				if (label != null) {
				
					writer.write(atom.getID().toString() + "->" +
						(label.isComplete() ? DiskADConstants.COMPLETE_LABEL_PREFIX : DiskADConstants.INCOMPLETE_LABEL_PREFIX) +
						atom.getLabel().toString());
					writer.write(System.getProperty("line.separator"));
				}
			}
			
			writer.flush();
			writer.close();
			
			System.out.println("done!");
			
		} catch (IOException e) {
			e.printStackTrace();
			throw new ADPersistenceException("A problem with writing term index: " + e.getMessage());
		}
	}*/

	private void saveTermBasedIndex(AtomicDecomposition ad, File dir) throws ADPersistenceException {

		try {
			
			System.out.print("Saving term-based index... ");
			
			File tiFile = IOUtils.createNewFile(dir.getAbsolutePath() + "/" + DiskADConstants.TERM_INDEX_FILE);
			Writer writer = new FileWriter(tiFile);
			
			for (URI term : ad.getTermBasedIndex().keySet()) {
				
				boolean first = true;
				//TODO Do we need to worry about individuals here? nominals?
				//if (!OntologyUtils.isIndexTerm(term)) continue;
				
				writer.write(term + "->");
				
				for (Atom atom : ad.getTermBasedIndex().get(term)) {
					
					writer.write((!first ? "," : "") + atom.getID());
					first = false;
				}
				
				writer.write(System.getProperty("line.separator"));
			}
			
			writer.flush();
			writer.close();
			
			System.out.println("done!");
			
		} catch (IOException e) {
			e.printStackTrace();
			throw new ADPersistenceException("A problem with writing term index: " + e.getMessage());
		}
	}

	private void saveGraph(AtomicDecomposition ad, File dir) throws ADPersistenceException {

		try {
			
			System.out.print("Saving graph... ");
			
			File graphFile = IOUtils.createNewFile(dir.getAbsolutePath() + "/" + DiskADConstants.GRAPH_FILE);
			Writer writer = new FileWriter(graphFile);
			GraphWriter<Atom, Object> graphWriter = new DOTWriterImpl<Atom, Object>();
			
			graphWriter.write(ad.getGraph(), writer);
			writer.flush();
			writer.close();
			
			System.out.println("done!");
			
		} catch (IOException e) {
			e.printStackTrace();
			throw new ADPersistenceException("A problem with writing the AD graph: " + e.getMessage());
		}
	}

	private void saveModuleType(AtomicDecomposition ad, File dir) throws ADPersistenceException {

		try {
			
			File mdFile = IOUtils.createNewFile(dir.getPath() + "/" + DiskADConstants.MODULE_TYPE_FILE);
			Writer writer = new FileWriter(mdFile);
			
			writer.write(ad.getModuleType().name());
			writer.flush();
			writer.close();
			
		} catch (IOException e) {
			e.printStackTrace();
			throw new ADPersistenceException("A problem with writing the module type's file: " + e.getMessage());
		}
	}
}
